package state.util;

import particle.core.tools.Matrix;
import particle.core.tools.PMath;
import particle.core.view.assets.Image;
import state.GameConstants;
import state.GameGlobal;
import state.GameImage;
import state.LoadResourceCompleteListener;
import state.ResourceManager;
import state.ResourceRms;
import state.util.array.ByteArray;

public class ImageUtil {
//  public static GameImage getImage(String fileName) {
//    return getImage(GameConstants.DEFAULT_RESOURCE_CATEGORY, fileName);
//  }

//  public static GameImage getCoreImage(String fileName) {
//    return getImageFromFolder(GameConstants.CORE_IMAGE_FOLDER, fileName);
//  }
//
//  private static GameImage getImageFromFolder(String folderName, String fileName) {
//    if (folderName.indexOf('/') != 0) {
//      folderName = "/" + folderName;
//    }
//    return GameImage.createImage1(folderName + "/" + fileName);
//  }

  public static ByteArray getResource(String category, String fileName) {
    Object value = null;
    Hashtable resourceByCategory = (Hashtable) GameGlobal.resourceCategory.get(category);
    if (resourceByCategory == null) {
      resourceByCategory = ResourceRms.loadMasterRecord(category);
      if (resourceByCategory != null) {
        GameGlobal.resourceCategory.put(category, resourceByCategory);
      }
    }

    if (resourceByCategory != null) {
      value = resourceByCategory.get(fileName);
      if (value != null) {
        return ResourceRms.getResourceAsByteArray(category, ((Integer) value).intValue());
      } else {
        if (GameGlobal.systemCanvas.isDebugMode()) {
          System.out.println("Can not find file: " + fileName + " in resource category " + category);
        }
      }
    } else {
      if (GameGlobal.systemCanvas.isDebugMode()) {
        System.out.println("Can not find master record for resource category: " + category);
      }
    }
    return null;
  }

  public static GameImage getImage(String category, String fileName) {
    Object value = null;
    Hashtable imageByCategory = (Hashtable) GameGlobal.resourceCategory.get(category);
    if (imageByCategory == null) {
      imageByCategory = ResourceRms.loadMasterRecord(category);
      if (imageByCategory != null) {
        GameGlobal.resourceCategory.put(category, imageByCategory);
      }
    }

    // Nếu là màn hình 320x240 thì lấy thử ảnh ngang xem có được không
    if (imageByCategory != null) {
      if (!GameConstants.IS_240x320_SCREEN) {
        int index = fileName.indexOf('.');
        String ext = fileName.substring(index + 1);
        String name = fileName.substring(0, index);

        value = imageByCategory.get(name + "_320240" + "." + ext);
        if (value == null) {
          value = imageByCategory.get(fileName);
        }
      } else {
        value = imageByCategory.get(fileName);
      }

      // Get image from rms
      if (value != null) {
        return ResourceRms.getImage(category, ((Integer) value).intValue());
      }
    }
    return ResourceManager.createImage(category, fileName);
  }

  /**
   * Ghép nhiều lần 1 ảnh nhỏ để tạo 1 ảnh lớn hơn
   * 
   * @param image - Ảnh nhỏ
   * @param width - Chiều rộng của ảnh lớn cần tạo
   * @param height - Chiều dài của ảnh lớn cần tạo
   * @return Ảnh lớn sau khi đã được ghép
   */
  public static GameImage joinAndCreateImages(GameImage image, int width, int height) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = joinAndCreateImages(image1, getInt("width"), getInt("height"));
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("width", width).putInt("height", height);
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }

    GameImage resultImage = GameImage.createImage2(width, height);
    int heightTime = height / image.getHeight();
    if (heightTime == 0) {
      heightTime = 1;
    }
    int widthTime = width / image.getWidth();
    if (widthTime == 0) {
      widthTime = 1;
    }
    int x = 0;
    int y = 0;
    for (int i = 0; i < heightTime; i++) {
      for (int j = 0; j < widthTime; j++) {
        image.getImage().drawToImage(resultImage.getImage(), x, y, 0, 0, image.getWidth(), image.getHeight());
        x += image.getWidth();
      }
      y += image.getHeight();
    }
    return resultImage;
  }

  /**
   * Lấy ra 1 ảnh là 1 phần của ảnh đã có
   * 
   * @param image Ảnh cũ
   * @param fromX Tọa độ X TOP-LEFT của khung hình lấy ra
   * @param fromY Tọa độ Y TOP-LEFT của khung hình lấy ra
   * @param newWidth Kích thước chiều ngang của khung hình lấy ra
   * @param newHeight Kích thước chiều dài của khung hình lấy ra
   * @return Ảnh con của ảnh đầu vào
   */
  public static GameImage getSubImage(GameImage image, int fromX, int fromY, int newWidth, int newHeight, boolean isTransparence) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = getSubImage(image1, getInt("fromX"), getInt("fromY"), getInt("newWidth"), getInt("newHeight"), ((GameBoolean) get("isTransparence")).booleanValue());
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("fromX", fromX).putInt("fromY", fromY).putInt("newWidth", newWidth).putInt("newHeight", newHeight).put("isTransparence", new GameBoolean(isTransparence));
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }

    Image newCoreImage = Image.newImage();
    newCoreImage.create(newWidth, newHeight, true, GameColor.WHITE_CODE);
    for (int i = 0; i < newWidth; i++) {
      for (int j = 0; j < newHeight; j++) {
        newCoreImage.setPixel(i, j, image.getImage().getPixel(fromX + i, fromY + j));
      }
    }
    return new GameImage(newCoreImage, null, null);
  }

  public static GameImage cloneImage(GameImage image) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = cloneImage(image1);
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName());
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }

    Image newCoreImage = Image.newImage();
    newCoreImage.create(image.getImage().getWidth(), image.getImage().getHeight(), true, GameColor.WHITE_CODE);
    image.getImage().drawToImage(newCoreImage, 0, 0, 0, 0, image.getImage().getWidth(), image.getImage().getHeight());
    return new GameImage(newCoreImage, null, null);
  }

  /**
   * Chuyển đổi tất cả các điểm mầu của ảnh thành sáng hơn
   * 
   * @param image - Ảnh cần làm sáng
   * @param rank - Độ làm sáng (phải nằm trong khoảng từ 0 đến 15)
   * @return - Ảnh sau khi đã làm sáng
   */
  public static GameImage makeBrighter(GameImage image, int rank) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = makeBrighter(image1, getInt("rank"));
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("rank", rank);
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }
    
    if (rank < 0 || rank > 15) {
      System.out.println("ImageUtil : makeBrighter : rank must be in [0..15]");
      return null;
    }

    Image newCoreImage = Image.newImage();
    newCoreImage.create(image.getImage().getWidth(), image.getImage().getHeight(), true, GameColor.WHITE_CODE);
    for (int i = 0; i < image.getWidth(); i++) {
      for (int j = 0; j < image.getHeight(); j++) {
        newCoreImage.setPixel(i, j, RGB.incr(image.getImage().getPixel(i, j), rank));
      }
    }
    return new GameImage(newCoreImage, null, null);
  }

  /**
   * Chuyển đổi tất cả các điểm mầu của ảnh thành tối hơn
   * 
   * @param image - Ảnh cần làm tối
   * @param rank - Độ làm tối (phải nằm trong khoảng từ 0 đến 15)
   * @return - Ảnh sau khi đã làm tối
   */
  public static GameImage makeDarker(GameImage image, int rank) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = makeDarker(image1, getInt("rank"));
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("rank", rank);
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }
    
    if (rank < 0 || rank > 15) {
      System.out.println("ImageUtil : makeDarker : rank must be in [0..15]");
      return null;
    }

    Image newCoreImage = Image.newImage();
    newCoreImage.create(image.getImage().getWidth(), image.getImage().getHeight(), true, GameColor.WHITE_CODE);
    for (int i = 0; i < image.getWidth(); i++) {
      for (int j = 0; j < image.getHeight(); j++) {
        newCoreImage.setPixel(i, j, RGB.decr(image.getImage().getPixel(i, j), rank));
      }
    }
    return new GameImage(newCoreImage, null, null);
  }

  /**
   * Zoom toàn bộ ảnh
   * 
   * @param src - Ảnh cần thay đổi
   * @param scale - Kích thước muốn thay đổi, 0 < scale < 1 nếu muốn thu nhỏ ảnh và > 1 nếu muốn phóng to ảnh
   * @return Ảnh sau khi zoom
   */
  public static GameImage resizeImage(GameImage src, float scale) {
    return resizeImage1(src, scale, 0, 0, false);
  }

  public static GameImage resizeImage2(GameImage src, int desWidth, int desHeight) {
    return resizeImage3(src, desWidth, desHeight, 0, 0, false);
  }

  public static GameImage resizeImage3(GameImage src, int desWidth, int desHeight, int px, int py, boolean isNeedToMakeTransparent) {
    if (src.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(src.getName()) {
        public void onLoadResourceDone(GameImage image) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = resizeImage3(image, getInt("desWidth"), getInt("desHeight"), getInt("px"), getInt("py"), ((GameBoolean) get("isNeedToMakeTransparent")).booleanValue());
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("desWidth", desWidth).putInt("desHeight", desHeight).putInt("px", px).putInt("py", py).put("isNeedToMakeTransparent", new GameBoolean(isNeedToMakeTransparent));
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }

    Image coreImage = Image.newImage();
    coreImage.create(desWidth, desHeight, true, GameColor.WHITE_CODE);
    Matrix matrix = new Matrix();
    matrix.scale(desWidth * 1.0f / src.getWidth(), desHeight * 1.0f / src.getHeight());
    src.getImage().transformR(coreImage, null, matrix);
    return new GameImage(coreImage, null, null);
  }

  /**
   * Zoom 1 phần của ảnh
   * 
   * @param src - Ảnh cần thay đổi
   * @param scale - Kích thước muốn thay đổi, 0 < scale < 1 nếu muốn thu nhỏ ảnh và > 1 nếu muốn phóng to ảnh
   * @param px - tọa độ x xác định của khoảng ảnh cần zoom
   * @param py - tọa độ y xác định của khoảng ảnh cần zoom
   * @param d - kích thước của khoảng hình vuông cần zoom
   * @return Ảnh sau khi zoom
   */
  public static GameImage resizeImage1(GameImage src, float scale, int px, int py, boolean isNeedToMakeTransparent) {
    if (src.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(src.getName()) {
        public void onLoadResourceDone(GameImage image) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = resizeImage1(image, getDouble("scale"), getInt("px"), getInt("py"), ((GameBoolean) get("isNeedToMakeTransparent")).booleanValue());
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putDouble("scale", scale).putInt("px", px).putInt("py", py).put("isNeedToMakeTransparent", new GameBoolean(isNeedToMakeTransparent));
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }
    
    if (scale < 0) {
      System.out.println("ImageUtil : resizeImage1 : scale must be greater than 0");
      return null;
    }

    int srcW = src.getWidth();
    int srcH = src.getHeight();
    int dstW = (int) (srcW * scale);
    int dstH = (int) (srcH * scale);
    return resizeImage3(src, dstW, dstH, px, py, isNeedToMakeTransparent);
  }

  public static GameImage rotate(GameImage image, int degrees) {
    if (image.getImage() == null) {
      GameImage emptyImage = ResourceManager.createEmptyImage();
      LoadResourceCompleteListener listener = new LoadResourceCompleteListener(image.getName()) {
        public void onLoadResourceDone(GameImage image1) {
          GameImage targetImage = ResourceManager.getImage(ResourceManager.EMPTY_CATEGORY, getString("imageName"));
          GameImage tempImage = rotate(image1, getInt("degrees"));
          targetImage.setImage(tempImage.getImage());
        }
      }.put("imageName", emptyImage.getName()).putInt("degrees", degrees);
      ResourceManager.addLoadImageCompleteListener(listener);
      return emptyImage;
    }

    Image coreImage = Image.newImage();
    int max = PMath.max(image.getWidth(), image.getHeight());
    coreImage.create(max, max, true, 0x00000000);
    Matrix matrix = new Matrix();
    matrix.rotateDWithAnchor(degrees, max / 2, max / 2);
    image.getImage().transformR(coreImage, null, matrix);
    
    // Trim image after rotate
    int left = max;
    int right = 0;
    int top = max;
    int bottom = 0;
    
    for (int x = 0; x < coreImage.getWidth(); x++) {
      for (int y = 0; y < coreImage.getHeight(); y++) {
        if (coreImage.getPixel(x, y) != 0) {
          if (x < left) {
            left = x;
          }
          if (x > right) {
            right = x;
          }
          if (y < top) {
            top = y;
          }
          if (y > bottom) {
            bottom = y;
          }
        }
      }
    }
    
    Image newCoreImage = Image.newImage();
    newCoreImage.create(right - left, bottom - top, true, 0x00000000);
    coreImage.drawToImage(newCoreImage, 0, 0, left, top, right - left, bottom - top);
    return new GameImage(newCoreImage, null, null);
  }

  public static GameImage transformMirror(GameImage gameImage) {
    // TODO: Particle : implement transformMirror
    return gameImage;
  }
}
